module i2s_clk_gen #(
    parameter BIT = 32
)(
    input  wire clk_50m,  // 输入系统时钟 50 MHz
    input  wire rst_n,    // 低有效复位
    output reg  bclk,     // 输出 I2S bit clock 3.072 MHz
    output reg  lrclk     // 输出 I2S word select 48 kHz
);

    // ========================
    // DDS分频产生bclk = 3.072MHz
    // ========================
    // step = 2^32 * (3.072e6 / 50e6) = 263402291
    localparam [31:0] STEP_BCLK = 32'd263402291;

    reg [31:0] phase_acc_bclk;
    always @(posedge clk_50m or negedge rst_n) begin
        if (!rst_n) begin
            phase_acc_bclk <= 0;
            bclk <= 0;
        end else begin
            phase_acc_bclk <= phase_acc_bclk + STEP_BCLK;
            bclk <= phase_acc_bclk[31]; // 取MSB为输出
        end
    end

    // ========================
    // bclk -> lrclk (48kHz)
    // ========================
    // 对于I2S：LRCLK周期 = 64 * BCLK周期
    reg [5:0] lr_cnt;

    always @(negedge bclk or negedge rst_n) begin
        if (!rst_n) begin
            lr_cnt <= 0;
            lrclk <= 0;
        end else begin
            if (lr_cnt == (2*BIT - 1)) begin
                lr_cnt <= 0;
                lrclk <= 0;
            end else begin
                if (lr_cnt == (BIT - 1))
                    lrclk <= 1;
                lr_cnt <= lr_cnt + 1'b1;
            end
        end
    end

endmodule
module i2s_reciever(
    input   wire    bclk,	//bit clock
    input   wire	lrclk,	//lrclock
	input	wire	sdata,	//data in
	input	wire	rst_n,	//reset signal
	
	output	reg	[23:0]	ldata,	//
	output	reg	[23:0]	rdata,	//
	output	reg	ldata_vld,
	output	reg	rdata_vld
);
	
	reg i;
	
	/*判断lrclk的上升沿与下降沿*/
	reg	lrclk_d;
	always @(negedge bclk or negedge rst_n) begin
		//接收到复位信号时
		if(!rst_n) begin
			lrclk_d <= 1'b0;
		end
		//在比特时钟的每一个下降沿,存储当前lrclk的情况
		else begin
			lrclk_d <= lrclk;
		end
	end
	//生成下降沿与上升沿的标志位
	wire lrclk_rising = {lrclk_d,lrclk} == 2'b01;
	wire lrclk_falling = {lrclk_d,lrclk} == 2'b10;
	
	
	/* 主接收逻辑：在BCLK的下降沿采样数据*/
	reg [4:0]	bit_counter;	//用于计算已接收的数据的计数器
	reg	[23:0]	rdata_shreg;	//右声道数据移位寄存器
	reg	[23:0]	ldata_shreg;	//右声道数据移位寄存器
	always @(negedge bclk or negedge rst_n) begin
		//复位逻辑
		if(!rst_n) begin
			bit_counter <= 5'd31;
			ldata <= 24'd0;
			rdata <= 24'd0;
			ldata_vld <= 1'b0;
			rdata_vld <= 1'b0;
			ldata_shreg <= 24'd0;
			rdata_shreg <= 24'd0;		
		end
		else begin
			//默认情况下，将有效标志位拉低
			ldata_vld <= 1'b0;
			rdata_vld <= 1'b0;
			

			//当lrclk出现上升沿与下降沿时，重置计数器
			if(lrclk_rising || lrclk_falling) begin
				bit_counter <= 5'd31;
				ldata_shreg <= 24'd0;
				rdata_shreg <= 24'd0;
			end
			else if (bit_counter > 0) begin
                bit_counter <= bit_counter - 5'd1;
            end

			//当bit_counter的值大于5时，持续接收数据
			/* 1.先判断当前为左声道还是右声道
			** 2.再判断计数器是否为最大值，若是，则先空过一位
			** 3.再判断计数器的值是否为7（31-24），若是，则将数据有效标志位设置为高电平，将移位寄存器中的数据转移值输出端口
			** 4.上述情况均不满足，则存储数据
			** 5.所有逻辑判断完成后，计数器-1
			*/
			
			//若为左声道
			if(!lrclk) begin
				if(bit_counter == 0 || bit_counter > 5'd8) begin
					ldata_shreg <= {ldata_shreg[22:0], sdata};
				end
				else if (bit_counter == 5'd8) begin
					ldata <= ldata_shreg;
					ldata_vld <= 1'b1;
					ldata_shreg <= 24'd0;
				end
				else if(bit_counter == 5'd1) begin
					ldata <= 24'd0;
				end
			end
			//若为右声道
			if(lrclk) begin
				if(bit_counter == 0 || bit_counter > 5'd8) begin
					rdata_shreg <= {rdata_shreg[22:0], sdata};
				end
				else if (bit_counter == 5'd8) begin
					rdata <= rdata_shreg;
					rdata_vld <= 1'b1;
					rdata_shreg <= 24'd0;
				end
				else if(bit_counter == 5'd1) begin
					rdata <= 24'd0;
				end

			end
		end
	end
	
endmodule

module i2s_recieve_top(
    input   wire    i_clk_50m,      //主时钟输入，连接至片上晶振（50MHz）
    input   wire    i_rst_n,        //复位信号输入
    //i2s物理接口
    input   wire    i_i2s_sdata,    //串行数据输入
    output  wire    o_i2s_mclk,     //主时钟输出
    output  wire    o_i2s_bclk,     //bitclock输出
    output  wire    o_i2s_lrclk,    //lrclock输出
    //数据输出（连接至下一模块）
    output  wire    [23:0]  o_i2s_rxdata_l,     //
    output  wire    [23:0]  o_i2s_rxdata_r,     //
    output  wire    o_i2s_rxdata_vld_l,
	output  wire    o_i2s_rxdata_vld_r
);

	/*内部连线*/
	assign o_i2s_mclk = i_clk_50m;
	
	/*模块连接*/
	//必要的端口总线定义
	wire	o_i2s_bclk_inst;
	assign	o_i2s_bclk = o_i2s_bclk_inst;
	
	wire	o_i2s_lrclk_inst;
	assign	o_i2s_lrclk = o_i2s_lrclk_inst;
	
	wire	i_rst_n_inst;
	assign	i_rst_n_inst = i_rst_n;
	
	//i2s_clk_gen模块
	i2s_clk_gen u_is2_clk_gen  #(
		.DIV	(20),
		.BIT	(32)
	)(
    .clk_50m	(i_clk_50m),
    .rst_n		(i_rst_n_inst),
    .bclk		(o_i2s_bclk_inst),
    .lrclk		(o_i2s_lrclk_inst)
	);
	
	//i2s_reciever模块
	i2s_reciever u_i2s_reciever(
    .bclk		(o_i2s_bclk_inst),	//bit clock
    .lrclk		(o_i2s_lrclk_inst),	//lrclock
	.sdata		(i_i2s_sdata),	//data in
	.rst_n		(i_rst_n_inst),	//reset signal
	
	.ldata		(o_i2s_rxdata_l),	//
	.rdata		(o_i2s_rxdata_r),	//
	.ldata_vld	(o_i2s_rxdata_vld_l),
	.rdata_vld	(o_i2s_rxdata_vld_r)
	);
	
endmodule
module i2s_transmitter(
	input	wire	bclk,
	input	wire	lrclk,
	input	wire	rst_n,
	input	wire	data_vld,	//前级更改信号成功后，此位置1
	input	wire	[15:0]	rdata,
	input	wire	[15:0]	ldata,
	
	output	reg		ready,	//可作为信号指示前级发送下一组信号
	output	reg		sdata	
);

	/*LRCLK 边缘检测*/
	reg	lrclk_d;
	always @(negedge bclk or negedge rst_n) begin
		//接收到复位信号时
		if(!rst_n) begin
			lrclk_d <= 1'b0;
		end
		//在比特时钟的每一个下降沿,存储当前lrclk的情况
		else begin
			lrclk_d <= lrclk;
		end
	end
	//生成下降沿与上升沿的标志位
	wire lrclk_rising = {lrclk_d,lrclk} == 2'b01;
	wire lrclk_falling = {lrclk_d,lrclk} == 2'b10;
	
	/*主传输逻辑*/
	reg	[15:0]	ldata_s;
	reg [15:0]	rdata_s;
	reg	[15:0]	data_shift;
	reg	[3:0]	bit_counter;
	
	always @(negedge bclk or negedge rst_n) begin
		if(!rst_n) begin
			ldata_s <= 16'b0;
			rdata_s <= 16'b0;
			data_shift <= 16'b0;
			bit_counter <= 4'b0;
			ready <= 1'b1;
			sdata <= 1'b0;
			lrclk_d <= 1'b0;
		end
		else begin
			//正常状态下
			ready <= 1'b1;
			sdata <= 1'b0;
			//当检测到上升沿时,准备传输右声道信号
			if(lrclk_rising) begin
				 if (data_vld && ready) begin
					ldata_s <= ldata;
					rdata_s <= rdata;
					ready <= 1'b0;
				end
				data_shift <= rdata;
				bit_counter <= 4'd15;
				sdata <= rdata[15];  // 发送右声道MSB
			end
			//当检测到下降沿时,准备传输左声道信号
			else if(lrclk_falling) begin
				data_shift <= ldata_s;
				bit_counter <= 4'd15;
				sdata <= ldata_s[15];  // 发送MSB
			end
			// 正常数据移位
			else if (bit_counter > 0) begin
				sdata <= data_shift[bit_counter-1];
				bit_counter <= bit_counter - 4'd1;
			end
		end
	end


endmodule
module i2s_transmit_top(
    input   wire    i_clk_50m,      //主时钟输入，连接至片上晶振（50MHz）
    input   wire    i_rst_n,        //复位信号输入
	//前级数据传入
	input   wire    [15:0]  i_i2s_txdata_l,     //
    input   wire    [15:0]  i_i2s_txdata_r,     //
	input	wire	i_i2s_txdata_vld,
    //i2s物理接口
    output  wire    o_i2s_sdata,    //串行数据输出
    output  wire    o_i2s_mclk,     //主时钟输出
    output  wire    o_i2s_bclk,     //bitclock输出
    output  wire    o_i2s_lrclk,    //lrclock输出
    //其他数据输出（连接至下一模块）
    output  wire    o_i2s_tx_ready	//可作为信号指示前级发送下一组信号
);

	//内部连线
	assign o_i2s_mclk = i_clk_50m;
	
	/*模块连接与整合*/
	//必要的端口总线定义
	wire	o_i2s_bclk_inst;
	assign	o_i2s_bclk = o_i2s_bclk_inst;
	
	wire	o_i2s_lrclk_inst;
	assign	o_i2s_lrclk = o_i2s_lrclk_inst;
	
	wire	i_rst_n_inst;
	assign	i_rst_n_inst = i_rst_n;
	//时钟产生模块
	//i2s_clk_gen模块
	i2s_clk_gen #(
		.DIV	(20),
		.BIT	(16)
	)u_is2_clk_gen(
    .clk_50m	(i_clk_50m),
    .rst_n		(i_rst_n_inst),
    .bclk		(o_i2s_bclk_inst),
    .lrclk		(o_i2s_lrclk_inst)
	);
	
	//i2s_transmitter 模块
	i2s_transmitter u_i2s_transmitter(
    .bclk		(o_i2s_bclk_inst),
    .lrclk		(o_i2s_lrclk_inst),
    .rst_n		(i_rst_n_inst),
	.data_vld	(i_i2s_txdata_vld),
	.rdata		(i_i2s_txdata_r),
	.ldata		(i_i2s_txdata_l),
	
	.ready		(o_i2s_tx_ready),
	.sdata		(o_i2s_sdata)
	);
	
endmodule
	
	
